package com.reptile.handle;

import com.alibaba.fastjson.JSON;
import com.common.exception.BaseException;
import com.common.util.FastJsonUtils;
import com.common.util.RedisUtil;
import com.reptile.constant.YsReptileConstant;
import com.reptile.context.BaseContext;
import com.reptile.dto.MaterialDTO;
import com.reptile.dto.ReptileDataDTO;
import com.reptile.service.YsMaterialService;
import com.reptile.service.execute.SouGoPicExecute;
import com.reptile.service.execute.WallHavenPicExecute;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 图片定时任务处理类
 *
 * @author songyafei
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class YsPictureHandle {


    private final YsMaterialService ysMaterialService;

    @Resource
    private RedisUtil redisUtil;

    /**
     * 爬取搜狗图片
     */
    @XxlJob("YsReptileSouGouPicHandler")
    @Transactional(rollbackFor = Exception.class)
    @Retryable(value = Exception.class,maxAttempts = 3,
            backoff = @Backoff(delay = 5000, multiplier = 1, maxDelay = 10000))
    public void SouGouPicExecute() throws Exception {
        try {
            log.info("开始爬取搜狗图片数据！");
            BaseContext baseContext = new BaseContext(new SouGoPicExecute());
            List<MaterialDTO> result = baseContext.baseExecute();
            log.info("爬取搜狗图片数据结束！{}", JSON.toJSONString(result));
            //保存到数据库
            ysMaterialService.saves(result);
        }catch (Exception e){
            throw new Exception(e);
        }
    }

    /**
     * 爬取WallHaven图片
     */
    @XxlJob("YsReptileWallHavenPicHandler")
    @Transactional(rollbackFor = Exception.class)
    @Retryable(value = Exception.class,maxAttempts = 3,
            backoff = @Backoff(delay = 5000, multiplier = 1, maxDelay = 10000))
    public void WallHavenPicExecute() throws Exception {
        log.info("开始爬取WallHaven图片数据！");
        ReptileDataDTO reptileDataDTO = FastJsonUtils.getJson(redisUtil.spop(YsReptileConstant.PIC_WALL_HAVEN_KEY), ReptileDataDTO.class);
        BaseContext baseContext = new BaseContext(new WallHavenPicExecute());
        List<MaterialDTO> result = new ArrayList<>();
        int errorIndex = 0;
        try{
            for (int i = reptileDataDTO.getStart(); i <= reptileDataDTO.getEnd(); i++) {
                errorIndex = i;
                log.info("开始爬取WallHaven第{}页数据", i);
                String newUrl = reptileDataDTO.getUrl() + i;
                List<MaterialDTO> MaterialDTOItems = baseContext.baseExecute(newUrl);
                log.info("爬取WallHaven第{}页数据结束，数据{}",i,JSON.toJSONString(MaterialDTOItems));
                if (CollectionUtils.isEmpty(MaterialDTOItems)){
                    continue;
                }
                result.addAll(MaterialDTOItems);
            }
            log.info("爬取WallHaven图片数据结束！{}", JSON.toJSONString(result));
            //保存到数据库
            ysMaterialService.saves(result);
            //记录本次爬取的数据到redis
            setNewReptileDataToRedis(reptileDataDTO);
        }catch (Exception e){
            log.error("爬取第{}页WallHaven图片发生异常",errorIndex);
            //记录本次爬取的异常数据到redis
            reptileDataDTO.setEnd(errorIndex);
            setNewReptileDataToRedis(reptileDataDTO);
            throw new Exception(e);
        }
    }

    /**
     * 重新计算爬取进度
     * @param reptileDataDTO
     */
    private void setNewReptileDataToRedis(ReptileDataDTO reptileDataDTO) {
        ReptileDataDTO newReptileDataDTO = ReptileDataDTO.builder()
                .start(reptileDataDTO.getEnd())
                .end(reptileDataDTO.getEnd() + reptileDataDTO.getDefaultPage())
                .url(YsReptileConstant.WALL_HAVEN_PIC)
                .build();
        //更新redis页数信息
        redisUtil.sadd(YsReptileConstant.PIC_WALL_HAVEN_KEY, JSON.toJSONString(newReptileDataDTO));
        //设置过期时间
        redisUtil.expire(YsReptileConstant.PIC_WALL_HAVEN_KEY,999999,0);
    }


    @Recover
    public void recover(Exception e) {
        log.warn("重试机制执行完毕！");
    }
}
